﻿namespace UnitTests.Foundation
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;

    /// <summary>
    /// Test context, establishing common grounds for one or more tests.
    /// </summary>
    public abstract class TestContext : IDisposable
    {
        private readonly Stack<Action> _teardownActions;

        /// <summary>
        /// Initializes a new instance of the <see cref="TestContext"/> class.
        /// </summary>
        public TestContext()
        {
            _teardownActions = new Stack<Action>();
        }

        /// <summary>
        /// Gets the teardown actions. Teardown actions will be executed when this test context is disposed.
        /// </summary>
        /// <value>The teardown actions.</value>
        public Stack<Action> TeardownActions
        {
            get { return _teardownActions; }
        }

        /// <summary>
        /// Gets the local executing path.
        /// </summary>
        /// <returns>Path of the assembly currently executing.</returns>
        public virtual string GetLocalExecutingPath()
        {
            return new Uri(Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase)).LocalPath;
        }

        /// <summary>
        /// Performns any initialization of the test context.
        /// </summary>
        public virtual void Initialize()
        {
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                while (_teardownActions.Count > 0)
                {
                    Action teardown = _teardownActions.Pop();
                    if (teardown != null)
                        teardown.Invoke();
                }
            }
        }
    }
}